import math
import re

from utils.pursuit_utils import haversine


def is_valid_license_plate(plate):
    """
    验证车牌号是否合法（中国大陆车牌）
    支持格式：
    1. 常规车牌：省份汉字 + 字母 + 5位字母/数字（如：京A12345）
    2. 新能源车牌：
       - 小型车：省份汉字 + 字母 + 字母/D/F + 5位数字（如：京AD12345）
       - 大型车：省份汉字 + 字母 + 5位数字 + 字母/D/F（如：京A12345D）

    参数：
        plate (str): 待验证的车牌字符串

    返回：
        bool: 如果车牌合法返回True，否则返回False
    """
    # 省份简称列表
    provinces = "京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领"

    # 常规车牌正则表达式
    standard_pattern = re.compile(
        r'^[' + provinces + r']([A-HJ-NP-Z]|[A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳])$'
    )

    # 新能源车牌正则表达式
    new_energy_pattern = re.compile(
        r'^[' + provinces + r'][A-HJ-NP-Z](?:[0-9]{5}[DF]|[DF][0-9]{5})$'
    )

    # 武警车牌正则表达式
    armed_police_pattern = re.compile(
        r'^WJ[' + provinces + r'][0-9]{4}[0-9A-Z]$'
    )

    # 军车车牌正则表达式
    military_pattern = re.compile(
        r'^[A-Z]{2}[0-9]{5}$'
    )

    # 去除空格并转为大写
    plate = plate.strip().upper()

    # 检查车牌长度（常规车牌7位，新能源车牌8位）
    if len(plate) not in (7, 8):
        return False

    # 匹配各种车牌类型
    if (standard_pattern.fullmatch(plate) or
            new_energy_pattern.fullmatch(plate) or
            armed_police_pattern.fullmatch(plate) or
            military_pattern.fullmatch(plate)):
        return True

    return False


def get_radar_paths(radar_data):
    # 找到所有起点（Upstream 为 None 的雷达）
    start_nodes = [sn for sn, data in radar_data.items() if data['Upstream'] is None]

    paths = []
    for start_sn in start_nodes:
        path = []
        current_sn = start_sn
        while current_sn is not None:
            path.append(current_sn)
            downstream = radar_data[current_sn]['Downstream']
            current_sn = downstream['sn'] if downstream else None
        paths.append(path)

    return paths


def is_vehicle_passed_gantry(vehicle_lon, vehicle_lat, vehicle_heading, gantry_lon, gantry_lat, distance_threshold=30,
                             angle_threshold=45):
    """
    判断车辆是否经过门架
    :param vehicle_lat: 车辆纬度
    :param vehicle_lon: 车辆经度
    :param vehicle_heading: 车辆航向角（度，从正北顺时针方向）
    :param gantry_lat: 门架纬度
    :param gantry_lon: 门架经度
    :param distance_threshold: 距离阈值（米），默认100米
    :param angle_threshold: 角度阈值（度），默认30度
    :return: True（经过）或False（未经过）
    """
    # 计算车辆与门架的距离
    distance = haversine(vehicle_lon, vehicle_lat, gantry_lon, gantry_lat)
    if distance > distance_threshold:
        return False

    # 计算车辆到门架的方位角
    bearing = haversine(vehicle_lon, vehicle_lat, gantry_lon, gantry_lat)

    # 计算车辆航向与方位角的夹角
    angle_diff = abs((vehicle_heading - bearing + 180) % 360 - 180)
    if angle_diff <= angle_threshold:
        return True
    else:
        return False


def is_vehicle_passing_checkpoint(
        vehicle_lon, vehicle_lat, vehicle_heading,  # 车辆经度、纬度、航向角（0-360°，正北为0）
        checkpoint_lon, checkpoint_lat,  # 卡口经度、纬度
        max_distance=30,  # 最大允许距离（米）
        max_angle_diff=45  # 最大允许航向角偏差（°）
) -> bool:
    """
    判断车辆是否经过卡口
    :param vehicle_lon: 车辆经度
    :param vehicle_lat: 车辆纬度
    :param vehicle_heading: 车辆航向角（0-360°，正北为0）
    :param checkpoint_lon: 卡口经度
    :param checkpoint_lat: 卡口纬度
    :param max_distance: 最大允许距离（米），默认50米
    :param max_angle_diff: 最大允许航向角偏差（°），默认45°
    :return: True（经过） / False（未经过）
    """
    # 1. 计算车辆与卡口的距离（Haversine公式，单位：米）
    lon1, lat1, lon2, lat2 = map(math.radians, [vehicle_lon, vehicle_lat, checkpoint_lon, checkpoint_lat])
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
    distance = 6371000 * 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))  # 地球半径6371km → 6371000米

    if distance > max_distance:
        return False  # 距离太远，不可能经过

    # 2. 计算车辆航向角是否指向卡口
    # 计算车辆到卡口的方位角（0-360°，正北为0）
    y = math.sin(dlon) * math.cos(lat2)
    x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dlon)
    bearing = (math.degrees(math.atan2(y, x)) + 360) % 360

    # 计算航向角偏差（取最小值，因为360°和0°是相同的）
    angle_diff = abs(vehicle_heading - bearing) % 360
    angle_diff = min(angle_diff, 360 - angle_diff)

    if angle_diff > max_angle_diff:
        return False  # 航向角偏差太大，车辆未朝向卡口

    # 3. 满足条件：距离足够近 + 航向角匹配
    return True


def calculate_catch_down_time(
        v_A0,  # 车辆A的初始速度 (m/s)
        v_B,  # 车辆B的速度 (恒定, m/s)
        a_A,  # 车辆A的减速度 (m/s², 正值)
        n,  # 车辆A减速百分比 (%)
        lon_A, lat_A,  # 车辆A的经纬度
        lon_B, lat_B  # 车辆B的经纬度
):
    """
    计算车辆B追上减速的车辆A的时间。

    返回:
        (减速时间, 匀速时间):
            - 如果在减速阶段追上，匀速时间为0。
            - 如果在匀速阶段追上，返回实际的匀速时间。
            - 如果无法追上，匀速时间为None。
    """
    # 计算初始距离
    D0 = haversine(lon_A, lat_A, lon_B, lat_B)

    # 车辆A减速后的速度
    v_A1 = v_A0 * (1 - n / 100)

    # 减速时间
    t_dec = (v_A1 - v_A0) / (-a_A)

    # 减速阶段行驶距离
    D_dec = v_A0 * t_dec + 0.5 * (-a_A) * t_dec ** 2

    # 检查是否在减速阶段追上
    # 解方程: 0.5*(-a_A)*t^2 + (v_A0 - v_B)*t - D0 = 0
    a = 0.5 * (-a_A)
    b = v_A0 - v_B
    c = -D0
    discriminant = b ** 2 - 4 * a * c

    if discriminant >= 0:
        sqrt_discriminant = math.sqrt(discriminant)
        t1 = (-b + sqrt_discriminant) / (2 * a)
        t2 = (-b - sqrt_discriminant) / (2 * a)
        valid_times = [t for t in [t1, t2] if 0 <= t <= t_dec]

        if valid_times:
            t_catch = min(valid_times)
            return (t_catch, 0)  # 在减速阶段追上

    # 检查是否在匀速阶段追上
    if v_A1 < v_B:
        t_const = (D0 + v_A1 * t_dec - D_dec) / (v_B - v_A1)
        if t_const > t_dec:
            return (t_dec, t_const)  # 在匀速阶段追上

    # 无法追上
    return (t_dec, None)


def extract_and_convert(data: str) -> int:
    """
    从给定字符串中提取最后一个 '-' 之前的部分，去掉 '-' 并转为整数。

    Args:
        data (str): 输入字符串，例如 '121221-12-173298821'

    Returns:
        int: 转换后的整数，例如 12122112
    """
    last_dash_index = data.rfind('-')  # 找到最后一个 '-' 的位置
    part_before_last_dash = data[:last_dash_index]  # 提取最后一个 '-' 之前的部分
    number_str = part_before_last_dash.replace('-', '')  # 去掉中间的 '-'
    return int(number_str)  # 转为整数


def get_radar_paths(radar_data):
    # 找到所有起点（Upstream 为 None 的雷达）
    start_nodes = [sn for sn, data in radar_data.items() if data['Upstream'] is None]

    paths = []
    for start_sn in start_nodes:
        path = []
        current_sn = start_sn
        while current_sn is not None:
            path.append(current_sn)
            downstream = radar_data[current_sn]['Downstream']
            current_sn = downstream['sn'] if downstream else None
        paths.append(path)

    return paths
